#include "message.h"
#include "math.h"

#include <QDebug>
#include <QIODevice>
#include <QDir>

Message::Message()
{
    init();
}

Message::Message(const QByteArray &buffer)
{
    init();
    parseBuffer(buffer);
}

Message::Message(QIODevice *device)
{
    init();
    parseBuffer(device);
}

Message::~Message()
{
    head.clear();
    m_bodyFile.remove();
}

void Message::init()
{
    m_bodyFile.setFileTemplate(QDir::tempPath()+"/msg_XXXXXXX.tmp");
//    QDir dir(QDir::tempPath()+"/scripter");
//    if(!dir.exists())
//        dir.mkdir(QDir::tempPath()+"/scripter");
//    m_bodyFile.setFileName(QDir::tempPath()+"/scripter/ServTmp.xml");
    m_bodyFile.setAutoRemove(false);
}

void Message::setParam(const QString &name, const QString &value)
{
    head[name]=value;
}
const QString & Message::getParam(const QString &parName)
{
    return head[parName];
}
#include "unzip.h"
QByteArray Message::getBody()
{
//    if( getParam("ZIP").toInt() == 2) {
//        UnZip::ErrorCode ec;
//        UnZip uz;
//        m_bodyFile.close();
//        qDebug()<<m_bodyFile.fileName();
//        ec = uz.openArchive(&m_bodyFile);
//        if (ec != UnZip::Ok) {
//            qDebug() << "Failed to open archive: " << uz.formatError(ec).toAscii().data();
//            return QByteArray();
//        }
//        QString extractPath = QDir::tempPath();
//        QDir dir(extractPath);
//        if(!dir.exists())
//            dir.mkdir(extractPath);
//        ec = uz.extractAll(extractPath);
//        if (ec != UnZip::Ok) {
//            qDebug() << "Extraction failed: " << uz.formatError(ec).toAscii().data();
//            uz.closeArchive();
//            return QByteArray();
//        }
//        m_bodyFile.remove();
//        m_bodyFile.setFileName(extractPath + "/ServTmp.xml");
//        setParam("ZIP","0");
//    }
    QByteArray res;
    if( m_bodyFile.size() > 0) {
        if(m_bodyFile.isOpen())
            m_bodyFile.reset();
        else
            m_bodyFile.open();
        res.reserve(m_bodyFile.size());

        while(!m_bodyFile.atEnd()) {
            QByteArray ba = m_bodyFile.read(1024);
            res.append(ba);
        }
    }

    return res;
}

quint32 Message::getMessageLength() // Длинна сообщения состоит из заголовка(сумма длин всех параметров) и тела сообщения
{
    quint32 length = 0;
    head[PR_MESSAGE_LENGTH] = "";
    length += strlen(HEADEND);
    length += strlen(BODYEND);
    QMap<QString, QString>::iterator i;
    for (i = head.begin(); i != head.end(); ++i)
    {
        length += i.key().length();
        length += i.value().length();
        length += 2; // equal and semicolon
    }
    length += m_bodyFile.size();
    int lenLength = log10((double)length)+1; // lenLength - длинна длинны LOL
    QString len1, len2;
    len1 = QString::number(length);
    len2 = QString::number(lenLength + length);
    if(len2.length() > len1.length())
        lenLength += len2.length() - len1.length();
    length += lenLength; // Добавим еще длинну самой цифры length например длинна цифры '100' - 3 символа
    head[PR_MESSAGE_LENGTH] = QString::number(length);
    return length;
}

void Message::parseBuffer(const QByteArray &buffer)
{
    head.clear();
    int headEndPos = buffer.indexOf(HEADEND); // Найдем ползицию конца заголовка
    QByteArray tmpHead = buffer.left(headEndPos);// Отделили байты отвечающие за заголовок
    QList<QByteArray> params = tmpHead.split(';');// Разбили на список массивов байт
    for(int i = 0; i< params.length()-1; i++)
    {
        QList<QByteArray> p = params[i].split('=');
        head[p[0]]=p[1];
    }
}

void Message::parseBuffer(QIODevice *device)
{
    Q_ASSERT(device);
    head.clear();
    QByteArray baHead;
    baHead.reserve(1280);
    if(device->isOpen())
        device->reset();
    else
        device->open(QIODevice::ReadOnly);

    QByteArray baStart = device->peek(3);
    if(baStart.contains("BIN"))
        device->read(7);

    char ch;
    while(!device->atEnd()) {
        device->getChar(&ch);
        baHead.append(ch);
        if(baHead.endsWith(HEADEND))
            break;
    }

    QList<QByteArray> params = baHead.split(';');
    for(int i = 0; i< params.length()-1; i++) {
        QList<QByteArray> p = params[i].split('=');
        head[p[0]]=p[1];
    }

    if(m_bodyFile.exists()) {
        qDebug()<< "REMOVE: "<< m_bodyFile.fileName();
        m_bodyFile.remove();        
    }

    m_bodyFile.open();
    while(!device->atEnd()) {
        baHead = device->read(1024);
        if(device->atEnd())
            m_bodyFile.write(baHead.left(baHead.length()-strlen(BODYEND)));
        else
            m_bodyFile.write(baHead);
    }
    qDebug()<<m_bodyFile.fileName();
    m_bodyFile.close();
}
#include "zip.h"
bool Message::packBody()
{
    Zip::ErrorCode ec;
    Zip uz;
    QString tempZipFile = QDir::tempPath() + "/toserv.zip";

    ec = uz.createArchive(tempZipFile);
    if (ec != Zip::Ok) {
        qDebug() << "Unable to create archive: " << uz.formatError(ec).toAscii().data();
        return false;
    }
    if(m_bodyFile.isOpen())
        m_bodyFile.close();

    ec = uz.addEntry(m_bodyFile.fileName(), "ServTmp.xml");
    if (ec != Zip::Ok) {
        qDebug() << "Unable to add directory: " << uz.formatError(ec).toAscii().data();
        return false;
    }

    m_bodyFile.remove();
    if (uz.closeArchive() != Zip::Ok) {
        qDebug() << "Unable to close the archive: " << uz.formatError(ec).toAscii().data();
        return false;
    }

    m_bodyFile.setFileName(tempZipFile);
    setParam("ZIP","2");

    return ec == Zip::Ok;
}

void Message::debug()
{
    qDebug()<<"*****Debug message*****";
    QMap<QString, QString>::iterator i;
    for (i = head.begin(); i != head.end(); ++i)
    {
        qDebug() << i.key() << "-" << i.value();
    }
    qDebug()<<"body_size:"<<m_bodyFile.size();
    qDebug()<<"************************";
}

